package vn.edu.hut.soict.alignment.ui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

import vn.edu.hut.soict.alignment.BiDirectionalSyllableAlignment;
import vn.edu.hut.soict.translate.utils.StringUtils;

public class AlignmentPanel extends JPanel implements MouseListener {
	private static final long serialVersionUID = -617731151504386984L;

	private String viSentence;
	private String enSentence;

	private List<JButton> viButtonList;
	private List<JButton> enButtonList;

	private int buttonWidth = 60;
	private int buttonHeight = 30;
	private JButton selected;
	private JButton source;
	private JButton destination;
	private JLabel alignmentLabel;

	private BiDirectionalSyllableAlignment alignment;

	public AlignmentPanel() {
		super(new GridBagLayout());
		setDoubleBuffered(true);
		viButtonList = new ArrayList<JButton>();
		enButtonList = new ArrayList<JButton>();
	}

	public AlignmentPanel(String viSentence, String enSentence, String alignmentCode) {
		super(new GridBagLayout());
		setDoubleBuffered(true);
		this.viSentence = viSentence;
		this.enSentence = enSentence;
		viButtonList = new ArrayList<JButton>();
		enButtonList = new ArrayList<JButton>();
		alignmentLabel = new JLabel(alignmentCode);
		source = null;
		destination = null;
		initResources();
		displayResources();
		if (alignmentCode == null || alignmentCode.equals("")) {
			alignment = new BiDirectionalSyllableAlignment(viSentence, enSentence);
		}
		else {
			alignment = new BiDirectionalSyllableAlignment(viSentence, enSentence, alignmentCode);
		}
	}

	private void initResources() {
		List<String> viSyllables = StringUtils.splitIntoSyllable(viSentence);
		for (int i = 0; i < viSyllables.size(); i++) {
			JButton button = new JButton(viSyllables.get(i));
			button.setPreferredSize(new Dimension(buttonWidth, buttonHeight));
			button.setMargin(new Insets(2, 2, 2, 2));
			button.setActionCommand("vi " + i);
			button.addMouseListener(this);
			viButtonList.add(button);
		}
		JButton extraViButton = new JButton("");
		extraViButton.setPreferredSize(new Dimension(buttonWidth, buttonHeight));
		extraViButton.setMargin(new Insets(2, 2, 2, 2));
		extraViButton.setActionCommand("vi " + viSyllables.size());
		extraViButton.addMouseListener(this);
		viButtonList.add(extraViButton);

		List<String> enSyllables = StringUtils.splitIntoSyllable(enSentence);
		for (int i = 0; i < enSyllables.size(); i++) {
			JButton button = new JButton(enSyllables.get(i));
			button.setPreferredSize(new Dimension(buttonWidth, buttonHeight));
			button.setMargin(new Insets(2, 2, 2, 2));
			button.setActionCommand("en " + i);
			button.addMouseListener(this);
			enButtonList.add(button);
		}
		JButton extraEnButton = new JButton("");
		extraEnButton.setPreferredSize(new Dimension(buttonWidth, buttonHeight));
		extraEnButton.setMargin(new Insets(2, 2, 2, 2));
		extraEnButton.setActionCommand("en " + enSyllables.size());
		extraEnButton.addMouseListener(this);
		enButtonList.add(extraEnButton);
	}

	private void displayResources() {
		GridBagConstraints c = new GridBagConstraints();

		c.insets = new Insets(5, 5, 40, 5);
		for (int i = 0; i < viButtonList.size(); i++) {
			c.gridx = i;
			c.gridy = 0;
			add(viButtonList.get(i), c);
		}

		c.insets = new Insets(40, 5, 5, 5);
		for (int i = 0; i < enButtonList.size(); i++) {
			c.gridx = i;
			c.gridy = 1;
			add(enButtonList.get(i), c);
		}
		
		c.insets = new Insets(10, 5, 5, 5);
		c.gridx = 0;
		c.gridy = 2;
		add(new JLabel("Gióng hàng:", JLabel.RIGHT), c);
		
		c.gridx = 1;
		c.gridy = 2;
		c.gridwidth = Math.max(viButtonList.size() - 1, enButtonList.size() - 1) + 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		alignmentLabel.setPreferredSize(new Dimension(30, 50));
		add(alignmentLabel, c);
	}

	private void updateSelection() {
		if (source == null) {
			source = selected;
			drawSelect(source);
		}
		else if (destination == null) {
			if (source == selected) {
				clearSelect(source);
				source = null;
			}
			else if (source.getActionCommand().substring(0, 2).equals(selected.getActionCommand().substring(0, 2))) {
				clearSelect(source);
				source = selected;
				drawSelect(source);
			}
			else {
				destination = selected;
				drawSelect(destination);
			}
		}
		else {
			clearSelect(source);
			clearSelect(destination);
			source = selected;
			drawSelect(source);
			destination = null;
		}

		if (source != null && destination != null) {
			if (!source.getActionCommand().substring(0, 2).equals("vi")) {
				JButton temp = source;
				source = destination;
				destination = temp;
			}
			updateAlignment();
		}
	}

	private void updateAlignment() {
		Integer sourceIndex = Integer.parseInt(source.getActionCommand().substring(3));
		Integer destinationIndex = Integer.parseInt(destination.getActionCommand().substring(3));
		if (sourceIndex == viButtonList.size() - 1) {
			sourceIndex = null;
		}
		if (destinationIndex == enButtonList.size() - 1) {
			destinationIndex = null;
		}
		boolean result = alignment.addToAlignment(sourceIndex, destinationIndex);
		if (!result) {
			alignment.deleteFromAlignment(sourceIndex, destinationIndex);
		}
		alignmentLabel.setText(alignment.alignmentToString(BiDirectionalSyllableAlignment.NORMAL_MODE));
		repaint();
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (alignment != null) {
			for (int sourceIndex = 0; sourceIndex < viButtonList.size() - 1; sourceIndex++) {
				List<Integer> destinationIndexList = alignment.destinationIndexesAlignWith(sourceIndex);
				if (destinationIndexList != null) {
					for (Integer destinationIndex : destinationIndexList) {
						if (destinationIndex == null) {
							destinationIndex = enButtonList.size() - 1;
						}
						drawAlignmentLine(g, sourceIndex, destinationIndex);
					}
				}
			}
			List<Integer> destinationIndexList = alignment.destinationIndexesAlignWith(null);
			if (destinationIndexList != null) {
				int sourceIndex = viButtonList.size() - 1;
				for (Integer destinationIndex : destinationIndexList) {
					if (destinationIndex == null) {
						destinationIndex = enButtonList.size() - 1;
					}
					drawAlignmentLine(g, sourceIndex, destinationIndex);
				}
			}
		}
	}

	private void drawAlignmentLine(Graphics g, int i, int j) {
		Graphics2D g2 = (Graphics2D) g;
		int x1 = viButtonList.get(i).getLocation().x + buttonWidth / 2;
		int y1 = viButtonList.get(i).getLocation().y + buttonHeight;
		int x2 = enButtonList.get(j).getLocation().x + buttonWidth / 2;
		int y2 = enButtonList.get(j).getLocation().y;
		g2.setColor(Color.BLUE);
		g2.setStroke(new BasicStroke(2));
		g2.drawLine(x1, y1, x2, y2);
		g2.setStroke(new BasicStroke(1));
	}

	private void drawSelect(JButton button) {
		button.setBorder(BorderFactory.createLineBorder(Color.red));
	}

	private void clearSelect(JButton button) {
		button.setBorder(BorderFactory.createLineBorder(Color.GRAY));
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		Object target = e.getSource();
		if (target instanceof JButton) {
			JButton button = (JButton) target;
			String actionCommand = button.getActionCommand();
			List<JButton> buttonList = null;
			if (actionCommand.startsWith("vi")) {
				buttonList = viButtonList;
			}
			else {
				buttonList = enButtonList;
			}
			int index = Integer.parseInt(actionCommand.substring(3));
			selected = buttonList.get(index);
			updateSelection();
		}
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	public void resetAlignment() {
		alignment = new BiDirectionalSyllableAlignment(viSentence, enSentence);
		repaint();
	}

	public String alignmentCode() {
		return alignment.alignmentToString(BiDirectionalSyllableAlignment.NORMAL_MODE);
	}
}
